package com.lll.simple.rpc.protocol.decoder;

import com.lll.simple.rpc.common.*;
import com.lll.simple.rpc.protocol.MsgType;
import com.lll.simple.rpc.protocol.ProtocolConstants;
import com.lll.simple.rpc.protocol.serialization.RpcSerialization;
import com.lll.simple.rpc.protocol.serialization.SerializationFactory;
import com.lll.simple.rpc.protocol.serialization.SerializationTypeEnum;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

/**
 * @Author: liull
 * @Description: 字节流数据解码为消息对象： 1.只有当ByteBuf长度大于消息头长度时候，才开始读取数据
 * 2.开始读取数据时，很肯能读取到的消息内容不是一个完整的报文，所以在开始读时，要标记读的索引， 以便在消息内容不够时候进行重置读锁引
 * 3.根据不同的报文类型MsgType，需要反序列化出不同的协议体对象。在 RPC 请求调用的场景下，
 * 服务提供者需要将协议体内容反序列化成 MiniRpcRequest 对象；在 RPC 结果响应的场景下，
 * 服务消费者需要将协议体内容反序列化成 MiniRpcResponse 对象。
 * @Date: Created in 14:42 2021/2/4
 * @Modified By:
 */
public class RpcDecoder extends ByteToMessageDecoder {
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        if (in.readableBytes() > ProtocolConstants.HEADER_TOTAL_LEN) { // 长度大于18，才开始读取数据
            in.markReaderIndex();
            short magic = in.readShort();
            if (magic != ProtocolConstants.MAGIC) {
                throw new IllegalArgumentException("magic number is illegal, " + magic);
            }
            byte version = in.readByte();
            byte serialType = in.readByte();
            byte type = in.readByte();
            byte status = in.readByte();
            long requestId = in.readLong();
            int msgLen = in.readInt();
            if (in.readableBytes() < msgLen) {
                in.resetReaderIndex();
                return;
            }

            MessageHeader header = new MessageHeader();
            header.setStatus(status);
            header.setMsgType(type);
            header.setMsgLen(msgLen);
            header.setVersion(version);
            header.setMagic(magic);
            header.setSerialization(serialType);
            header.setRequestId(requestId);

            byte[] body = new byte[msgLen];
            in.readBytes(body);
            RpcSerialization serialization = SerializationFactory.getSerializationByType(serialType);
            if (type == MsgType.REQUEST.getType()) {
                RpcProtocol<RpcRequest> protocol = new RpcProtocol<>();
                protocol.setHeader(header);
                RpcRequest data = serialization.deserialize(body, RpcRequest.class);
                protocol.setBody(data);
                out.add(protocol);
            } else if (type == MsgType.RESPONSE.getType()) {
                RpcProtocol<RpcResponse> protocol = new RpcProtocol<>();
                protocol.setHeader(header);
                RpcResponse data = serialization.deserialize(body, RpcResponse.class);
                protocol.setBody(data);
                out.add(protocol);
            } else {
                // TODO 心跳机制
                // MsgType.HEARTBEAT
                RpcProtocol<RpcHeartBeat> protocol = new RpcProtocol<>();
                protocol.setHeader(header);
                RpcHeartBeat data = serialization.deserialize(body, RpcHeartBeat.class);
                protocol.setBody(data);
                out.add(protocol);
            }
        }
    }
}
